package com.junxonline.plat.shiro.realm;


import com.google.gson.Gson;
import com.junxonline.plat.dao.model.Menu;
import com.junxonline.plat.dao.model.Position;
import com.junxonline.plat.dao.model.Role;
import com.junxonline.plat.dao.model.User;
import com.junxonline.plat.dao.repository.UserRepository;
import com.junxonline.common.exception.CommonBizException;
import com.junxonline.common.util.CommonUtils;
import com.junxonline.common.util.JWTUtils;
import com.junxonline.common.util.NetWorkUtils;
import com.junxonline.plat.shiro.token.CommonToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author JunX
 * @ClassName: DefaultRealm
 * @Description: 默认安全域
 */

@Service
@Transactional
public class CommonRealm extends AuthorizingRealm {

    private Logger logger = LogManager.getLogger();

    @Autowired
    private UserRepository userRepository;

    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        // 解密获得username，用于和数据库进行对比
        String username = JWTUtils.getUsername(token);
        if (null == username) {
            throw CommonBizException.TOKEN_AUTH_IS_ERROR;
        }

        User user = userRepository.findByUsername(username);
        if (CommonUtils.isEmpty(user)) {
            throw CommonBizException.ACCOUNT_IS_NOT_FINDED;
        }

        if (! JWTUtils.verify(token, username, user.getPassword())) {
            throw CommonBizException.ACCOUNT_OR_PASSWORD_IS_ERROR;
        }

        // 通过认证后做的事情 视为登录成功
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 更新最后登录IP地址和时间
            user.setLastLoginTime(new Date(System.currentTimeMillis()));
            user.setLastLoginIp(NetWorkUtils.getIpAddress(request));
            userRepository.save(user);
        } catch (Exception e) {
            throw CommonBizException.SYSTEM_ERROR;
        }

        return new SimpleAuthenticationInfo(token, token, getName());
    }

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = JWTUtils.getUsername(principalCollection.toString());
        if (null == username) {
            throw CommonBizException.TOKEN_AUTH_IS_ERROR;
        }
        User user = userRepository.findByUsername(username);
        if (CommonUtils.isEmpty(user)) {
            throw CommonBizException.ACCOUNT_IS_NOT_FINDED;
        }

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        List<Role> roles = user.getRoles();
        List<Position> positions = user.getPositions();

        Set<Menu> menus = new HashSet<Menu>();

        for (Role role : roles) {
            authorizationInfo.addRole(role.getRoleKey());
            menus.addAll(role.getMenus());
        }

        for (Position position : positions) {
            authorizationInfo.addRole(position.getPositionName());
            menus.addAll(position.getMenus());
        }

        Gson gson = new Gson();

        logger.info("当前用户授予角色和岗位：" + gson.toJson(authorizationInfo.getRoles()));

        for (Menu menu : menus) {
            authorizationInfo.addStringPermission(menu.getMenuPermission());
        }

        logger.info("当前用户授予权限：" + gson.toJson(authorizationInfo.getStringPermissions()));

        return authorizationInfo;
    }

    /**
     * 必须重写此方法
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof CommonToken;
    }

}
